package org.ehe.business.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.ehe.business.engineer.domain.EngineerEntity;
import org.ehe.business.engineer.domain.EngineerLevelConfigEntity;
import org.ehe.business.engineer.mapper.EngineerLevelConfigMapper;
import org.ehe.business.engineer.mapper.EngineerMapper;
import org.ehe.business.engineer.service.QuarterlyScoreService;
import org.ehe.business.overdue.config.OverdueStatus;
import org.ehe.business.project.domain.*;
import org.ehe.business.project.domain.bo.ProjectEntityBo;
import org.ehe.business.project.domain.dto.CompleteProjectRequest;
import org.ehe.business.project.domain.dto.ProjectCreateRequest;
import org.ehe.business.project.domain.dto.ProjectSearchRequest;
import org.ehe.business.project.domain.vo.ProjectProgressVO;
import org.ehe.business.project.domain.vo.ProjectVo;
import org.ehe.business.project.mapper.ProjectAssignmentMapper;
import org.ehe.business.project.mapper.ProjectMapper;
import org.ehe.business.project.service.ProjectDifficultyConfigService;
import org.ehe.business.project.service.ProjectService;
import org.ehe.business.timeout.contants.BizTypeConstant;
import org.ehe.business.timeout.event.BusinessEvent;
import org.ehe.business.timeout.mapper.TimeoutConfigMapper;
import org.ehe.common.core.constant.ProjectConstants;
import org.ehe.common.core.domain.dto.StartProcessDTO;
import org.ehe.common.core.domain.dto.StartProcessReturnDTO;
import org.ehe.common.core.enums.BusinessStatusEnum;
import org.ehe.common.core.exception.BusinessException;
import org.ehe.common.core.service.WorkflowService;
import org.ehe.common.core.utils.DateUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.common.satoken.utils.LoginHelper;
import org.ehe.erp.enums.ErpAuditStatus;
import org.ehe.system.domain.vo.SysOssVo;
import org.ehe.system.domain.vo.SysUserVo;
import org.ehe.system.service.ISysOssService;
import org.ehe.system.service.ISysUserService;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author :zhangnn
 * @className :ProjectServiceImpl
 * @description: TODO
 * @date 2025-07-16 11:17:24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, ProjectEntity> implements ProjectService {

    private final ProjectAssignmentMapper assignmentMapper;
    private final EngineerMapper engineerMapper;
    private final EngineerLevelConfigMapper levelConfigMapper;
    private final ProjectDifficultyConfigService difficultyConfigService;
    private final ISysOssService ossService;
    private final ApplicationEventPublisher eventPublisher;
    private final QuarterlyScoreService scoringService;
    private final WorkflowService workflowService;
    private final ProjectMapper projectMapper;
    private final TimeoutConfigMapper timeoutConfigMapper;
    private final ISysUserService userService;
    //private final ProjectOverdueService projectOverdueService;

    //private final TimeoutInstanceService instanceService;


    /**
     * * 创建项目
     */
    @Transactional
    public Long createProject(ProjectCreateRequest request) {
        request.setApproveStatus(String.valueOf(ErpAuditStatus.PENDING_SUBMIT.getStatus()));
        // 1. 验证层级限制
        if(request.getParentId() != null && request.getParentId() != 0){
            validateProjectLevel(request.getParentId());
        }
        // 2. 创建项目实体
        ProjectEntity project = buildProjectEntity(request);
        // 3. 生成项目编码
        project.setProjectCode(generateProjectCode());
        // 4. 根据难度计算时间
        calculateProjectDates(project, request);
        project.setCreateBy(LoginHelper.getUsername());
        // 5. 设置层级信息
        setProjectLevel(project, request.getParentId());

        //项目分配后，需要填写响应时间
        if(StringUtils.isNotBlank(project.getAssignedEngineer())){
            //默认1小时
            int hours = timeoutConfigMapper.getTimeByBizType(BizTypeConstant.PROJECT);
            project.setIsOverdueEndTime(LocalDateTime.now().plusHours(hours));
        }
        //状态未待提交
        this.baseMapper.insert(project);
        //6. 设置项目和设计的关系
        Long id = project.getId();

        //项目分配
        if(StringUtils.isNotBlank(request.getAssignedEngineer())){
            this.assignProject(id, Long.valueOf(request.getAssignedEngineer()));

            // 2. 发布任务分配事件，自动触发时效监控
            BusinessEvent event = new BusinessEvent(this, "TASK_ASSIGNED", "project", id);
            event.addContext("assignedEngineer", request.getAssignedEngineer());
            event.addContext("assignTime", LocalDateTime.now());
            eventPublisher.publishEvent(event);
            log.info("项目分配成功，已启动时效监控: projectId={}, engineerId={}", id, request.getAssignedEngineer());

            //发起工作流程
            StartProcessDTO process = new StartProcessDTO();
            Map<String,Object> map = new HashMap<>();
            map.put("type","projectAssign");
            EngineerEntity engineer = engineerMapper.selectById(request.getAssignedEngineer());
            Long userId = 1L;
            if(Objects.nonNull(engineer)){
                SysUserVo sysUserVo = userService.selectUserByUserName(engineer.getEmployeeCode());
                if(Objects.nonNull(sysUserVo)){
                    userId = sysUserVo.getUserId();
                }
            }

            map.put("engineer",userId);
            process.setVariables(map);
            process.setFlowCode("projectAssign");
            process.setBusinessId(String.valueOf(id));
            StartProcessReturnDTO processReturnDTO = workflowService.startWorkFlow(process);
            log.info("流程审批发起成功，已启动: projectId={}, engineerId={}", id, request.getAssignedEngineer());
            workflowService.completeTask(processReturnDTO.getTaskId(),"任务分配");
        }
        return id;
    }

    /**
     * 分配项目
     */
    public ProjectAssignmentEntity assignProject(Long projectId, Long engineerId) {
        ProjectEntity project = this.baseMapper.selectById(projectId);
        //EngineerEntity engineer = engineerMapper.selectById(engineerId);

        ProjectAssignmentEntity assignment = new ProjectAssignmentEntity();
        assignment.setProjectId(projectId);
        assignment.setEngineerId(engineerId);
        assignment.setAssignmentDate(LocalDateTime.now());
        assignment.setPlannedDays(project.getPlannedDays());
        assignment.setStatus(ProjectConstants.PROJECT_STATUS_WAIT);
        assignment.setCreateBy(LoginHelper.getUsername());
        assignmentMapper.insert(assignment);
        return assignment;
    }

    /**
     * 获取项目列表
     * @param project
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<ProjectVo> selectPageProjectList(ProjectEntityBo project, PageQuery pageQuery) {
        LambdaQueryWrapper<ProjectEntity> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(project.getProjectName()), ProjectEntity::getProjectName, project.getProjectName());
        lqw.like(StringUtils.isNotBlank(project.getProjectCode()), ProjectEntity::getProjectCode, project.getProjectCode());
        lqw.orderByDesc(ProjectEntity::getCreateTime);
        Page<ProjectVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }

    /**
     * 检查工程师是否可以接项目
     */
    private boolean canTakeProject(EngineerEntity engineer, ProjectEntity project) {
        QueryWrapper<EngineerLevelConfigEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("level", engineer.getCurrentLevel());
        EngineerLevelConfigEntity levelConfig = levelConfigMapper.selectOne(wrapper);

        String[] allowedDifficulties = levelConfig.getAllowedDifficulties().split(",");

        for (String difficulty : allowedDifficulties) {
            if (difficulty.trim().equals(project.getDifficultyName())) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取工程师的项目列表
     */
    public TableDataInfo<ProjectAssignmentEntity> getEngineerProjects(Long engineerId,PageQuery query) {
        QueryWrapper<ProjectAssignmentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("engineer_id", engineerId);
        Page<ProjectAssignmentEntity> projectAssignmentEntities = assignmentMapper.selectPage(query.build(),wrapper);
        projectAssignmentEntities.getRecords().forEach(a->{
            ProjectVo projectVo = projectMapper.selectVoById(a.getProjectId());
            if(Objects.nonNull(projectVo)){
                a.setProjectName(projectVo.getProjectName());
            }
        });
        return TableDataInfo.build(projectAssignmentEntities);
    }


    /**
     * 验证项目层级限制
     */
    private void validateProjectLevel(Long parentId) {
        if (parentId != null) {
            ProjectEntity parent = getById(parentId);
            if (parent == null) {
                throw new BusinessException("父级项目不存在");
            }
            if(null == parent.getLevel()){
                parent.setLevel(1);
            }
            if (parent.getLevel() >= 5) {
                throw new BusinessException("项目层级不能超过5层");
            }
        }
    }


    /**
     * 构建项目实体
     */
    private ProjectEntity buildProjectEntity(ProjectCreateRequest request) {
        ProjectEntity project = new ProjectEntity();
        project.setParentId(request.getParentId());
        project.setProjectName(request.getProjectName());
        project.setProjectType(request.getProjectType());
        project.setDifficultyId(request.getDifficultyId());
        project.setDifficultyName(request.getDifficultyName());
        project.setPriority(request.getPriority());
        project.setProjectLevel(request.getProjectLevel());
        project.setProjectStage(request.getProjectStage());
        project.setDescription(request.getDescription());
        project.setAssignedEngineer(request.getAssignedEngineer());
        project.setEngineerLevel(request.getEngineerLevel());
        project.setAttachmentFileIds(request.getAttachmentFileIds());
        project.setStatus(request.getStatus());
        project.setApproveStatus(request.getApproveStatus());

        //project.setDrawIds(request.getDrawIds());
        return project;
    }

    /**
     * 生成项目编码
     */
    private String generateProjectCode() {
        String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "EIAHE" + dateStr;

        // 查询当天最大编号
        List<String> ids = this.baseMapper.queryList(DateUtils.getDate());
        QueryWrapper<ProjectEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("project_code", prefix)
            .orderByDesc("project_code")
            .last("LIMIT 1");

        ProjectEntity lastProject = getOne(queryWrapper);


        int nextNum = 1;
        if (lastProject != null) {
            String lastCode = lastProject.getProjectCode();
            String numStr = lastCode.substring(prefix.length());
            nextNum = Integer.parseInt(numStr) + 1;
        } else {
            nextNum = ids.size() + 1;
        }

        return prefix + String.format("%05d", nextNum);
    }


    /**
     * 根据难度计算项目时间
     */
    private void calculateProjectDates(ProjectEntity project, ProjectCreateRequest request) {
        // 获取难度配置
        ProjectDifficultyConfigEntity difficultyConfig = difficultyConfigService.getByDifficulty(request.getDifficultyId());
        if (difficultyConfig == null) {
            throw new BusinessException("难度配置不存在：" + request.getDifficultyId());
        }

        project.setDifficultyScore(difficultyConfig.getScore());
        project.setPlannedDays(difficultyConfig.getDays());

        project.setDifficultyId(request.getDifficultyId());
        project.setDifficultyName(request.getDifficultyName());

        // 如果没有指定计划开始时间，则使用当前时间
        LocalDateTime startDate = request.getPlannedStartDate();
        if (startDate == null) {
            startDate = LocalDateTime.now();
        }

        // 如果没有指定计划结束时间，则根据难度天数计算
        LocalDateTime endDate = request.getPlannedEndDate();
        if (endDate == null) {
            endDate = startDate.plusDays(difficultyConfig.getDays());
        }

        project.setPlannedStartDate(startDate);
        project.setPlannedEndDate(endDate);
        project.setActualStartDate(request.getActualStartDate());
        project.setActualEndDate(request.getActualEndDate());
    }

    /**
     * 设置项目层级信息
     */
    private void setProjectLevel(ProjectEntity project, Long parentId) {
        if (parentId == null || parentId == 0) {
            // 顶级项目
            project.setLevel(1);
            project.setPath("/" + project.getId());
        } else {
            // 子项目
            ProjectEntity parent = getById(parentId);
            if(parent.getLevel() == null){
                parent.setLevel(1);
            }
            project.setLevel(parent.getLevel() + 1);
            project.setPath(parent.getPath() + "/" + project.getId());
        }
    }


    /**
     * 获取项目树形结构
     */
    @Override
    public List<ProjectEntity> getProjectTree(ProjectEntityBo bo) {
        // 1. 获取所有项目（不先筛选，因为需要判断父子关系）
        List<ProjectEntity> allProjects = this.baseMapper.selectList(null);

        // 2. 将所有项目转为 ID -> 实体 的Map，方便快速查找父节点
        Map<Long, ProjectEntity> projectMap = allProjects.stream()
            .collect(Collectors.toMap(ProjectEntity::getId, entity -> entity));

        // 3. 筛选出直接符合条件的项目
        List<ProjectEntity> matchProjects = allProjects.stream()
            .filter(project -> {
                // 查询工程师信息
                String assignedEngineerId = project.getAssignedEngineer();
                EngineerEntity engineerEntity = new EngineerEntity();
                if(StringUtils.isNotBlank(assignedEngineerId)){
                    engineerEntity = engineerMapper.selectById(Long.parseLong(assignedEngineerId));
                    //工程师名称
                    project.setAssignedEngineerName(engineerEntity.getName());
                }
                //计算时效进度
                project.setProcessRat(0.0);
                if(null != project.getActualStartDate() && null != project.getActualEndDate()){
                    LocalDateTime actualStartDate = project.getActualStartDate();
                    LocalDateTime actualEndDate = project.getActualEndDate();
                    long totalDays = ChronoUnit.SECONDS.between(actualStartDate, actualEndDate);
                    // 如果总天数为0（开始和截止是同一天）
                    if (totalDays <= 0) {
                        project.setProcessRat(1.0);
                    }
                    LocalDateTime today = LocalDateTime.now();
                    LocalDateTime compareDate = today.isAfter(actualEndDate) ? actualEndDate : today;
                    long passedDays = ChronoUnit.SECONDS.between(actualStartDate, compareDate);
                    // 避免出现负数
                    passedDays = Math.max(passedDays, 0);

                    project.setProcessRat(Math.round((double) passedDays / totalDays * 100) / 100.0);
                }

                //全部
                if(bo.getFlag().equals("1")){
                    if(StringUtils.isNotBlank(bo.getProjectName())){
                        return project.getProjectName().contains(bo.getProjectName());
                    }
                    return true;
                }
                //未分配
                if(bo.getFlag().equals("2")){
                    if(StringUtils.isNotBlank(bo.getProjectName())){
                        return project.getProjectName().contains(bo.getProjectName()) &&
                            StringUtils.isBlank(assignedEngineerId);
                    }
                    return StringUtils.isBlank(assignedEngineerId);
                }
                //我的
                if(bo.getFlag().equals("3")){
                    String currentUser = LoginHelper.getUsername();
                    // 如果项目未分配负责人，则不匹配
                    if (StringUtils.isBlank(assignedEngineerId)) {
                        return false;
                    }
                    try {
                        if (engineerEntity == null) {
                            return false;
                        }
                        if(StringUtils.isNotBlank(bo.getProjectName())){
                            return project.getProjectName().contains(bo.getProjectName()) &&
                                currentUser.equals(engineerEntity.getEmployeeCode());
                        }
                        // 检查工程师姓名是否匹配
                        return currentUser.equals(engineerEntity.getEmployeeCode());
                    } catch (NumberFormatException e) {
                        // 如果assignedEngineerId不是有效的数字，则不匹配
                        return false;
                    }
                }
                //查询超期的任务
                if(bo.getFlag().equals("4")){
                    markProjectStatus(project);
                    if(project.isOverdue()){
                        if(StringUtils.isNotBlank(bo.getProjectName())){
                            return project.getProjectName().contains(bo.getProjectName()) &&
                                project.isOverdue();
                        }
                        return project.isOverdue();
                    } else {
                        return false;
                    }
                }
                return true;
            })
            .peek(project -> {
                // 标记超期任务和未分配任务
                markProjectStatus(project);
            })
            .collect(Collectors.toList());

        // 4. 收集所有需要保留的节点ID：符合条件的节点 + 它们的所有祖先节点
        Set<Long> keepIds = new HashSet<>();
        for (ProjectEntity match : matchProjects) {
            // 递归收集当前节点及其所有父节点的ID
            collectAllAncestorIds(match.getId(), projectMap, keepIds);
        }

        // 5. 从所有项目中筛选出需要保留的节点（符合条件的节点 + 其祖先）
        List<ProjectEntity> filteredProjects = new ArrayList<>();
        if (keepIds.size() > 0) {
            filteredProjects = allProjects.stream()
                .filter(project -> keepIds.contains(project.getId()))
                .peek(project -> {
                    // 为所有保留的节点标记状态
                    markProjectStatus(project);
                })
                .collect(Collectors.toList());
        }
        // 如果没有匹配的项目，返回空列表

        // 6. 基于筛选后的节点构建树形结构
        return buildProjectTree(filteredProjects, 0L);
    }


    /**
     * 标记项目状态（超期任务和未分配任务）
     * @param project 项目实体
     */
    private void markProjectStatus(ProjectEntity project) {
        // 获取计划结束日期（LocalDateTime类型）和状态
        LocalDateTime actualEndDate = project.getActualEndDate();
        String status = project.getStatus();
        String assignedEngineerId = project.getAssignedEngineer();

        // 判断是否超期
        boolean isOverdue = false;
        if (actualEndDate != null && StringUtils.isNotBlank(status)) {
            // 获取当前日期时间
            LocalDateTime currentDateTime = LocalDateTime.now();

            // 超期条件：预计实际结束日期 < 当前日期时间 且 状态不是"已完成"
            boolean dateOverdue = actualEndDate.isBefore(currentDateTime);
            boolean notCompleted = ! ProjectConstants.PROJECT_STATUS_COMPLETED.equals(status);

            isOverdue = dateOverdue && notCompleted;
        }

        // 设置超期标记
        project.setOverdue(isOverdue);
        // 设置未分配标记
        project.setUnassigned(StringUtils.isBlank(assignedEngineerId));
    }

    /**
     * 递归收集节点自身及其所有祖先节点的ID
     * @param currentId 当前节点ID
     * @param projectMap 所有项目的ID映射
     * @param keepIds 要保留的节点ID集合
     */
    private void collectAllAncestorIds(Long currentId, Map<Long, ProjectEntity> projectMap, Set<Long> keepIds) {
        if (currentId == null || keepIds.contains(currentId)) return;

        // 1. 添加当前节点ID
        keepIds.add(currentId);

        // 2. 查找父节点
        ProjectEntity current = projectMap.get(currentId);
        if (current == null) {
            return;
        }
        Long parentId = current.getParentId();

        // 3. 如果父节点存在且不是根节点（parentId != 0），递归收集父节点
        if (parentId != null && parentId != 0L) {
            collectAllAncestorIds(parentId, projectMap, keepIds);
        }
    }


    /**
     * 构建项目树形结构
     */
    private List<ProjectEntity> buildProjectTree(List<ProjectEntity> allProjects, Long parentId) {
        return allProjects.stream()
            .filter(project -> {
                if (parentId == 0L) {
                    return project.getParentId() == 0L;
                } else {
                    return parentId.equals(project.getParentId());
                }
            })
            .map(project -> {
                // 递归获取子项目
                List<ProjectEntity> children = buildProjectTree(allProjects, project.getId());
                project.setChildren(children);
                return project;
            })
            .collect(Collectors.toList());
    }

    /**
     * 获取项目详情
     * @param projectId
     * @return
     */
    @Override
    public ProjectEntity getProjectDetail(Long projectId) {
        ProjectEntity project = getById(projectId);
        if (project == null) {
            throw new BusinessException("项目不存在");
        }
        EngineerEntity engineerEntity = engineerMapper.selectById(project.getAssignedEngineer());
        if(!Objects.isNull(engineerEntity)){
            project.setAssignedEngineerName(engineerEntity.getName());
        }
        //获取项目附件
        List<SysOssVo> vos = setProjectFiles(project);
        project.setOssVos(vos);

        // 获取子项目
        QueryWrapper<ProjectEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", projectId);
        List<ProjectEntity> children = list(queryWrapper);
        for (ProjectEntity child : children) {
            engineerEntity = engineerMapper.selectById(child.getAssignedEngineer());
            child.setAssignedEngineerName(engineerEntity.getName());
            List<SysOssVo> vos2 = setProjectFiles(child);
            child.setOssVos(vos2);
        }
        project.setChildren(children);
        return project;
    }

    /**
     * 获取项目附件信息
     * @param p
     */
    private List<SysOssVo> setProjectFiles(ProjectEntity p) {
        //获取附件
        String[] split2 = new String[0];
        List<SysOssVo> ovs2 = new ArrayList<>();

        if(StringUtils.isNotBlank(p.getAttachmentFileIds()) && p.getAttachmentFileIds().contains(",")){
            split2 = p.getAttachmentFileIds().split(",");
        } else {
            if(StringUtils.isNotBlank(p.getAttachmentFileIds())){
                SysOssVo vo = ossService.getById(Long.valueOf(p.getAttachmentFileIds()));
                ovs2.add(vo);
            }
        }
        Arrays.asList(split2).forEach(l->{
            SysOssVo vo = ossService.getById(Long.valueOf(l));
            ovs2.add(vo);
        });
       return ovs2;
    }


    /**
     * 修改项目
     * @param projectId
     * @param request
     */
    @Override
    @Transactional
    public void updateProject(Long projectId, ProjectCreateRequest request) {
        ProjectEntity existingProject = this.baseMapper.selectById(projectId);
        if (existingProject == null) {
            throw new BusinessException("项目不存在");
        }

        //去判断当前业务存在不存在流程
        String businessStatus = workflowService.getBusinessStatus(String.valueOf(projectId),"project");
        if(StringUtils.isBlank(businessStatus)
            || BusinessStatusEnum.isDraftOrCancelOrBack(businessStatus)
        ){
            //发起工作流程
            StartProcessDTO process = new StartProcessDTO();
            Map<String,Object> map = new HashMap<>();
            map.put("engineer",request.getAssignedEngineer());
            process.setVariables(map);
            process.setFlowCode("projectAssign");
            process.setBusinessId(String.valueOf(projectId));
            workflowService.startWorkFlow(process);
            log.info("流程审批发起成功，已启动: projectId={}, engineerId={}", projectId, request.getAssignedEngineer());

        }
        else {
            throw new RuntimeException("审批中/已审核，不允许修改");
        }


        // 更新基本信息
        existingProject.setParentId(request.getParentId());
        existingProject.setProjectName(request.getProjectName());
        existingProject.setProjectType(request.getProjectType());
        //existingProject.setDifficultyId(request.getDifficultyId());
        //existingProject.setDifficultyName(request.getDifficultyName());
        existingProject.setPriority(request.getPriority());
        existingProject.setProjectLevel(request.getProjectLevel());
        existingProject.setProjectStage(request.getProjectStage());
        existingProject.setDescription(request.getDescription());
        existingProject.setAssignedEngineer(request.getAssignedEngineer());
        existingProject.setEngineerLevel(request.getEngineerLevel());
        existingProject.setAttachmentFileIds(request.getAttachmentFileIds());
        existingProject.setUpdateBy(LoginHelper.getUsername());
        existingProject.setStatus(request.getStatus());
        // 如果难度发生变化，重新计算时间
        if (!existingProject.getDifficultyId().equals(request.getDifficultyId())) {
            calculateProjectDates(existingProject, request);
        } else {
            // 否则使用请求中的时间
            existingProject.setPlannedStartDate(request.getPlannedStartDate());
            existingProject.setPlannedEndDate(request.getPlannedEndDate());
            existingProject.setActualStartDate(request.getActualStartDate());
            existingProject.setActualEndDate(request.getActualEndDate());
        }
        //获取项目分配信息
        ProjectAssignmentEntity assignment = assignmentMapper.selectOne(new LambdaQueryWrapper<ProjectAssignmentEntity>()
            .eq(ProjectAssignmentEntity::getProjectId,projectId)
            .eq(ProjectAssignmentEntity::getEngineerId,request.getAssignedEngineer())
        );
        if(Objects.nonNull(assignment)){
            assignment.setDelFlag("1");
            assignmentMapper.deleteById(assignment);
            if(StringUtils.isNotBlank(request.getAssignedEngineer())){
                this.assignProject(projectId, Long.valueOf(request.getAssignedEngineer()));
            }
        } else {
            this.assignProject(projectId, Long.valueOf(request.getAssignedEngineer()));
        }
        // 2. 发布任务分配事件，自动触发时效监控
        BusinessEvent event = new BusinessEvent(this, "TASK_ASSIGNED", BizTypeConstant.PROJECT, projectId);
        event.addContext("assignedEngineer", request.getAssignedEngineer());
        event.addContext("assignTime", LocalDateTime.now());
        eventPublisher.publishEvent(event);

        log.info("项目分配成功，已启动时效监控: projectId={}, engineerId={}", projectId, request.getAssignedEngineer());

        this.baseMapper.updateById(existingProject);


    }

    /**
     * 更新项目状态
     */
    @Override
    public void updateProjectStatus(Long projectId, String status) {
        ProjectEntity project = getById(projectId);
        if (project == null) {
            throw new BusinessException("项目不存在");
        }

        project.setStatus(status);

        // 如果是开始项目，更新实际开始时间
        if (ProjectConstants.PROJECT_STATUS_IN_PROGRESS.equals(status) && project.getActualStartDate() == null) {
            project.setActualStartDate(LocalDateTime.now());
        }

        // 如果是完成项目，更新实际结束时间
        if (ProjectConstants.PROJECT_STATUS_COMPLETED.equals(status) && project.getActualEndDate() == null) {
            project.setActualEndDate(LocalDateTime.now());
        }
        //项目状态是驳回的时候
//        if(status.equals("驳回")){
//            //处理完成时间
//            project.setStatus("驳回待处理");
//            //处理提醒实例
//            TimeoutInstance instance = instanceService.getOne(new QueryWrapper<TimeoutInstance>().eq("biz_id",projectId));
//            instance.setDelFlag("1");
//            instance.setStatus("CANCELLED");
//            instanceService.updateById(instance);
//
//            //驳回的时候，需要重新计算时间
//            OverdueRecord overdueRecord = overdueRecordMapper.selectByBizTypeAndId(BizTypeConstant.PROJECT, projectId);
//            //默认1小时
//            overdueRecord.setDeadlineTime(LocalDateTime.now().plusHours(1));
//            overdueRecord.setUpdateTime(new Date());
//            overdueRecordMapper.insertOrUpdate(overdueRecord);
//        } else
        if(status.equals("已完成")){
            //项目状态如果是已完成的时候
            updateProjectAssigenmeengInfo(projectId, project);
        }
        //项目分配后，需要填写响应时间
        if(StringUtils.isNotBlank(project.getAssignedEngineerName()) && null == project.getIsFeedbackTimeout()){
            //默认1小时
            int hours = timeoutConfigMapper.getTimeByBizType(BizTypeConstant.PROJECT);
            project.setIsOverdueEndTime(LocalDateTime.now().plusHours(hours));
        }
        updateById(project);
    }

    private void updateProjectAssigenmeengInfo(Long projectId, ProjectEntity project) {
        ProjectAssignmentEntity assignment = assignmentMapper.selectOne(new LambdaQueryWrapper<ProjectAssignmentEntity>()
            .eq(ProjectAssignmentEntity::getProjectId, projectId)
            .eq(ProjectAssignmentEntity::getEngineerId, project.getAssignedEngineer())
        );
        if(assignment == null){
            throw new BusinessException("项目没有分配！");
        }

        CompleteProjectRequest cp = new CompleteProjectRequest();
        cp.setAssignmentId(assignment.getId());
        cp.setCompletionDateTime(LocalDateTime.now());
        if(project.getStatus().equals(ProjectConstants.PROJECT_STATUS_COMPLETED)){
            cp.setTestPassed(1);
        }else {
            cp.setTestPassed(0);
        }
        cp.setStatus(project.getStatus());
        cp.setPlayDays(project.getPlannedDays());

        scoringService.completeProject(cp);
    }

    /**
     * 删除项目（级联删除子项目）
     */
    @Override
    public void deleteProject(Long projectId) {
        ProjectEntity project = getById(projectId);
        if (project == null) {
            throw new BusinessException("项目不存在");
        }

        // 递归删除子项目
        deleteProjectAndChildren(projectId);
    }

    /**
     * 递归删除项目及其子项目
     */
    private void deleteProjectAndChildren(Long projectId) {
        // 查找子项目
        QueryWrapper<ProjectEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", projectId);
        List<ProjectEntity> children = list(queryWrapper);

        // 递归删除子项目
        for (ProjectEntity child : children) {
            deleteProjectAndChildren(child.getId());
        }

        // 删除当前项目
        removeById(projectId);
    }

    /**
     * 搜索项目
     */
    @Override
    public List<ProjectEntity> searchProjects(ProjectSearchRequest request) {
        QueryWrapper<ProjectEntity> queryWrapper = new QueryWrapper<>();

        if (StringUtils.isNotBlank(request.getKeyword())) {
            queryWrapper.and(wrapper ->
                wrapper.like("project_name", request.getKeyword())
                    .or()
                    .like("project_code", request.getKeyword())
                    .or()
                    .like("description", request.getKeyword())
            );
        }

        if (StringUtils.isNotBlank(request.getStatus())) {
            queryWrapper.eq("status", request.getStatus());
        }

        if (StringUtils.isNotBlank(request.getDifficultyName())) {
            queryWrapper.eq("difficulty", request.getDifficultyName());
        }

        if (StringUtils.isNotBlank(request.getAssignedEngineer())) {
            queryWrapper.eq("assigned_engineer", request.getAssignedEngineer());
        }

        queryWrapper.orderByDesc("create_time");

        return list(queryWrapper);
    }

    /**
     * 获取项目统计信息
     */
    @Override
    public Map<String, Object> getProjectStatistics() {
        Map<String, Object> statistics = new HashMap<>();

        // 项目总数
        long totalCount = count();
        statistics.put("totalCount", totalCount);

        // 按状态统计
        Map<String, Long> statusCount = list().stream()
            .collect(Collectors.groupingBy(ProjectEntity::getStatus, Collectors.counting()));
        statistics.put("statusCount", statusCount);

        // 按难度统计
        Map<String, Long> difficultyCount = list().stream()
            .collect(Collectors.groupingBy(ProjectEntity::getDifficultyName, Collectors.counting()));
        statistics.put("difficultyCount", difficultyCount);

        // 按工程师统计
        Map<String, Long> engineerCount = list().stream()
            .filter(project -> StringUtils.isNotBlank(project.getAssignedEngineer()))
            .collect(Collectors.groupingBy(ProjectEntity::getAssignedEngineer, Collectors.counting()));
        statistics.put("engineerCount", engineerCount);

        return statistics;
    }

    /**
     * 批量删除
     * @param projectIds
     */
    @Override
    public void batchDeleteProjects(List<Long> projectIds) {
        if (projectIds == null || projectIds.isEmpty()) {
            throw new BusinessException("项目ID列表不能为空");
        }

        for (Long projectId : projectIds) {
            ProjectEntity projectEntity = this.baseMapper.selectById(projectId);
            projectEntity.setDelFlag("1");

            this.baseMapper.updateById(projectEntity);
        }
    }

    /**
     * 批量更新状态
     * @param projectIds
     * @param status
     */
    @Override
    public void saveOrUpdateBatch1(List<Long> projectIds, String status) {
        if (projectIds == null || projectIds.isEmpty()) {
            throw new BusinessException("项目ID列表不能为空");
        }

        for (Long projectId : projectIds) {
            ProjectEntity projectEntity = this.baseMapper.selectById(projectId);
            projectEntity.setStatus(status);
            this.baseMapper.updateById(projectEntity);
        }
    }

    /**
     * 项目进度
     * @param startDate
     * @param endDate
     * @return
     */
    @Override
    public List<ProjectProgressVO> getProjectProgressReport(String startDate, String endDate) {
        List<ProjectProgressVO> progressList = this.baseMapper.selectProjectProgress(startDate, endDate);

        // 计算进度百分比和延期状态
        LocalDateTime now = LocalDateTime.now();
        for (ProjectProgressVO progress : progressList) {
            calculateProgress(progress, now);
        }

        return progressList;
    }

    /**
     * 计算项目进度
     */
    private void calculateProgress(ProjectProgressVO progress, LocalDateTime now) {
        LocalDateTime startDate = progress.getPlannedStartDate();
        LocalDateTime endDate = progress.getPlannedEndDate();

        if (startDate == null || endDate == null) {
            progress.setProgressPercentage(0.0);
            progress.setDelayStatus("正常");
            progress.setDelayDays(0);
            return;
        }

        // 计算实际天数
        if (progress.getActualStartDate() != null) {
            LocalDateTime actualEnd = progress.getActualEndDate() != null ?
                progress.getActualEndDate() : now;
            progress.setActualDays(
                (int) ChronoUnit.DAYS.between(progress.getActualStartDate(), actualEnd)
            );
        }

        // 计算进度百分比
        if (ProjectConstants.PROJECT_STATUS_COMPLETED.equals(progress.getStatus())) {
            progress.setProgressPercentage(100.0);
        } else if (ProjectConstants.PROJECT_STATUS_IN_PROGRESS.equals(progress.getStatus())) {
            if (progress.getActualStartDate() != null) {
                long totalDays = ChronoUnit.DAYS.between(startDate, endDate);
                long passedDays = ChronoUnit.DAYS.between(progress.getActualStartDate(), now);
                progress.setProgressPercentage(Math.min(100.0, (double) passedDays / totalDays * 100));
            }
        } else {
            progress.setProgressPercentage(0.0);
        }

        // 计算延期状态
        if (ProjectConstants.PROJECT_STATUS_COMPLETED.equals(progress.getStatus())) {
            if (progress.getActualEndDate() != null) {
                long delayDays = ChronoUnit.DAYS.between(endDate, progress.getActualEndDate());
                if (delayDays > 0) {
                    progress.setDelayStatus("延期");
                    progress.setDelayDays((int) delayDays);
                } else if (delayDays < 0) {
                    progress.setDelayStatus("提前");
                    progress.setDelayDays((int) Math.abs(delayDays));
                } else {
                    progress.setDelayStatus("正常");
                    progress.setDelayDays(0);
                }
            }
        } else if (ProjectConstants.PROJECT_STATUS_IN_PROGRESS.equals(progress.getStatus())) {
            if (now.isAfter(endDate)) {
                progress.setDelayStatus("延期");
                progress.setDelayDays((int) ChronoUnit.DAYS.between(endDate, now));
            } else {
                progress.setDelayStatus("正常");
                progress.setDelayDays(0);
            }
        } else {
            progress.setDelayStatus("正常");
            progress.setDelayDays(0);
        }
    }

    /**
     * 导出项目数据
     */
    public void exportProjects(HttpServletResponse response, String status, String difficulty) {
        try {
            // 查询项目数据
            QueryWrapper<ProjectEntity> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(status)) {
                queryWrapper.eq("status", status);
            }
            if (StringUtils.isNotBlank(difficulty)) {
                queryWrapper.eq("difficulty", difficulty);
            }
            queryWrapper.orderByDesc("create_time");

            List<ProjectEntity> projects = this.baseMapper.selectList(queryWrapper);

            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("项目数据_" +
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")), "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 创建Excel工作簿
            try (Workbook workbook = new XSSFWorkbook()) {
                Sheet sheet = workbook.createSheet("项目数据");

                // 创建表头
                Row headerRow = sheet.createRow(0);
                String[] headers = {"项目编码", "项目名称", "项目类型", "难度", "状态", "优先级",
                    "项目级别", "项目阶段", "指定工程师", "工程师级别", "计划开始日期", "计划结束日期",
                    "实际开始日期", "实际结束日期", "计划天数", "创建时间", "创建者", "项目描述"};

                for (int i = 0; i < headers.length; i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(headers[i]);
                }

                // 填充数据
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                for (int i = 0; i < projects.size(); i++) {
                    Row row = sheet.createRow(i + 1);
                    ProjectEntity project = projects.get(i);

                    row.createCell(0).setCellValue(project.getProjectCode());
                    row.createCell(1).setCellValue(project.getProjectName());
                    row.createCell(2).setCellValue(project.getProjectType());
                    row.createCell(3).setCellValue(project.getDifficultyName());
                    row.createCell(4).setCellValue(project.getStatus());
                    row.createCell(5).setCellValue(project.getPriority());
                    row.createCell(6).setCellValue(project.getProjectLevel());
                    row.createCell(7).setCellValue(project.getProjectStage());
                    row.createCell(8).setCellValue(project.getAssignedEngineer());
                    row.createCell(9).setCellValue(project.getEngineerLevel());
                    row.createCell(10).setCellValue(project.getPlannedStartDate() != null ?
                        project.getPlannedStartDate().format(formatter) : "");
                    row.createCell(11).setCellValue(project.getPlannedEndDate() != null ?
                        project.getPlannedEndDate().format(formatter) : "");
                    row.createCell(12).setCellValue(project.getActualStartDate() != null ?
                        project.getActualStartDate().format(formatter) : "");
                    row.createCell(13).setCellValue(project.getActualEndDate() != null ?
                        project.getActualEndDate().format(formatter) : "");
                    row.createCell(14).setCellValue(project.getPlannedDays());
                    row.createCell(15).setCellValue(project.getCreateTime());
                    row.createCell(16).setCellValue(project.getCreateBy());
                    row.createCell(17).setCellValue(project.getDescription());
                }

                // 自动调整列宽
                for (int i = 0; i < headers.length; i++) {
                    sheet.autoSizeColumn(i);
                }

                // 写入响应流
                workbook.write(response.getOutputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        } catch (IOException e) {
            throw new BusinessException("导出失败：" + e.getMessage());
        }
    }

    /**
     * 根据人员级别判断可以接受的项目难度
     * @param request
     * @return
     */
    @Override
    public String checkProjectDifficultyByLevel(ProjectCreateRequest request) {
        return this.checkAccept(request.getAssignedEngineer(),request.getDifficultyName());
    }

    public String checkAccept(String engineerId, String difficultyName) {
        EngineerEntity engineer = engineerMapper.selectById(engineerId);

        // 检查工程师是否可以接这个难度的项目
        QueryWrapper<EngineerLevelConfigEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("level", engineer.getCurrentLevel());
        EngineerLevelConfigEntity levelConfig = levelConfigMapper.selectOne(wrapper);

        String[] allowedDifficulties = levelConfig.getAllowedDifficulties().split(",");

        for (String difficulty : allowedDifficulties) {
            if (difficulty.trim().equals(difficultyName)) {
                return "";
            }
        }
        return "工程师职级与项目难度不匹配";
    }

    /**
     * 修改项目预估小时数
     * @param projectId
     * @param estimatedHours
     */
    @Override
    public void updateProjectEstimatedHours(Long projectId, int estimatedHours) {
        ProjectEntity project = this.baseMapper.selectById(projectId);
        project.setEstimatedHours(estimatedHours);
        //预计实际结束时间
        if(project.getActualStartDate() == null){
            project.setActualStartDate(LocalDateTime.now());
        }
        project.setActualEndDate(project.getActualStartDate().plusDays(estimatedHours));
        project.setTaskDeadline(project.getActualEndDate());
        project.setStatus(ProjectConstants.PROJECT_SOLUTION_NAME_SHZ);
        project.setApproveStatus(ErpAuditStatus.SUBMITTED.getStatus().toString());
        project.setIsOverdue(OverdueStatus.PROCESSED);
        //超期处理
        if(project.getIsOverdueEndTime().isBefore(LocalDateTime.now())){
            project.setIsOverdue(OverdueStatus.OVERDUE_AND_PROCESSED);
        }
        this.baseMapper.updateById(project);
    }

    /**
     * 提交审批
     * @param projectId
     * @return
     */
    @Override
    public ProjectEntity submitProject(Long projectId) {
        ProjectEntity project = this.baseMapper.selectById(projectId);
        if(project.getApproveStatus().equals(ErpAuditStatus.REJECTED.getStatus().toString())){
            project.setApproveStatus(String.valueOf(ErpAuditStatus.SUBMITTED.getStatus()));
        }
        this.baseMapper.updateById(project);

        //发起工作流程
        StartProcessDTO process = new StartProcessDTO();
        Map<String,Object> map = new HashMap<>();
        map.put("engineer",project.getAssignedEngineer());
        process.setVariables(map);
        process.setFlowCode("projectAssign");
        process.setBusinessId(String.valueOf(projectId));
        workflowService.startWorkFlow(process);
        log.info("流程审批发起成功，已启动: projectId={}, engineerId={}", projectId, project.getAssignedEngineer());
        return project;
    }

    /**
     * 审批通过
     * @param projectId
     * @param auditUser
     * @return
     */
    @Override
    public ProjectEntity approveProject(Long projectId, String auditUser) {
        ProjectEntity project = this.baseMapper.selectById(projectId);

        try {
            // 1. 更新方案状态为通过
            project.setApproveStatus(String.valueOf(ErpAuditStatus.APPROVE.getStatus()));

            this.baseMapper.updateById(project);
            log.info("项目审核通过，已取消超期监控: solutionId={}", projectId);
        } catch (Exception e) {
            log.error("审核通过失败: solutionId={}", project, e);
            throw new RuntimeException("审核通过失败", e);
        }
        return project;
    }

    /**
     * 审批拒绝
     */
    @Override
    public ProjectEntity rejectProject(Long projectId, String auditUser) {
        ProjectEntity project = this.baseMapper.selectById(projectId);
        try {
            // 1. 更新方案状态为驳回
            project.setApproveStatus(String.valueOf(ErpAuditStatus.REJECTED.getStatus())); // 3-驳回
            project.setIsOverdue("0");
            int hours = timeoutConfigMapper.getTimeByBizType(BizTypeConstant.SOLUTION);
            project.setIsOverdueEndTime(LocalDateTime.now().plusHours(hours));
            this.baseMapper.updateById(project);

            // 2. 启动超期监控
            log.info("项目审核拒绝成功，已启动超期监控: solutionId={}", projectId);

        } catch (Exception e) {
            log.error("审核拒绝失败: solutionId={}", projectId, e);
            throw new RuntimeException("审核拒绝失败", e);
        }
        return project;
    }
}
